#!/usr/bin/env python

import os
import gzip
import errno
import sys
import time
import socket
import os.path
import collections

CMDEND	= '\n'
CMDPUT	= 'put '
ERRNO_WOULDBLOCK = (errno.EWOULDBLOCK, errno.EAGAIN)
def geterrnofrome(e):
    if hasattr(e, 'errno'):
        return e.errno
    elif e.args:
        return e.args[0]
    else:
        return None

def progress(complete, total):
	percent = int(float(complete) / total * 100)
	j = '#' * percent
	sys.stdout.write(str(percent) + '% ||' + j + '->' + '\r')
	sys.stdout.flush()

class socketclient(object):
	_DEFAULT_PORT = 19898
	_ERRNO_WOULDBLOCK = (errno.EWOULDBLOCK, errno.EAGAIN)

	def __init__(self, port = _DEFAULT_PORT):
		self.remoteaddr = ('127.0.0.1', 19898)
		self.prompt = ''
		self.filename = ''
		self.file = None
		self.bufdeque = collections.deque()
		self.fileinfo = ''

	def init(self):
		try:
			self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM, 0)
			self.sock.setsockopt(socket.IPPROTO_TCP, socket.TCP_NODELAY, 1)
			self.sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
			self.sock.connect(self.remoteaddr)
		except socket.error as e:
			print e
			return -1

	def recvresponse(self):
		tmp = ''
		x = ''
		while True:
			try:
				x = self.sock.recv(1)	
                        except (IOError, OSError) as e:
                                if geterrnofrome(e) in ERRNO_WOULDBLOCK:
                                        break
                                elif geterrnofrome(e) == errno.EBADF:
                                        return None
                                else:
                                        return None
			if x == '\n':
				break
			else:
				tmp += x
		return tmp

	def readsockhandler(self, bufdeque):
                chunklen = 0
                while True:
                        try:
                                chunkdata = self.sock.recv(8 * 1024)
                                l = len(chunkdata)
                                chunklen += l
                                if l == 0:
                                        return 0
                        except (IOError, OSError) as e:
                                if geterrnofrome(e) in ERRNO_WOULDBLOCK:
                                        break
                                elif geterrnofrome(e) == errno.EBADF:
                                        return -1
                                else:
                                        return -1
                print 'chunkdata' + chunkdata
                if chunklen != 0:
                        bufdeque.append(chunkdata)
                return chunklen

        def writesockhandler(self, buf):
		try:
			sendlen = self.sock.send(buf)
		except (IOError, OSError) as e:
			if geterrnofrome(e) in ERRNO_WOULDBLOCK:
				pass
			elif geterrnofrome(e) == errno.EBADF:
				return -1
			else:
				return -1
		return sendlen
	
	def loop(self):
		while True:
			self.cmd = raw_input(self.prompt)
				
			if self.cmd == '' or self.cmd == '\n':
				continue

			start_index = 0
			end_index = len(self.cmd) - 1
			for x in self.cmd:
				if x == ' ': 	start_index += 1
				else:		break
			for y in self.cmd:
				if y == ' ':	end_index -= 1 
				else:		break

			if start_index >= end_index:
				print self.cmd + ' error'
				continue

			self.cmd = self.cmd[start_index : end_index + 1]
			if self.cmd == '\n':
				continue

			if self.cmd[0] == '!':
				os.system(self.cmd[1:])	

			elif self.cmd.startswith('put'):
				print '----put start'
				print self.filename
				self.filename = self.cmd.split(' ')[1] 	
				if self.filename.find(':') != -1:
					print 'filename ":" not allowed'
					continue
				try:
					statres = os.stat(self.filename)
					self.file = open(self.filename, 'rb')
				except (OSError, IOError) as e:
					if self.file: 	self.file.close()
					print 'open file:' + self.filename + 'error' 
					continue
				
				self.fileinfo = CMDPUT  + self.filename + ':' + str(statres.st_size) + CMDEND
				
				print 'fileinfo : ' + self.fileinfo
				if self.writesockhandler(self.fileinfo) != len(self.fileinfo):
					print 'send fileinfo error'
					self.file.close()
					continue
			
				if self.recvresponse() != 'FILEINFO OK':
					self.file.close()
					continue	

				print 'FILEINFO OK' + str(statres.st_size)
				sendlen = 0
				flag = False
				while sendlen < statres.st_size:
					tmp = self.file.read(8 * 1024)
					print 'filedata:' + tmp
					if self.writesockhandler(tmp) != len(tmp):
						print 'send file data error'
						flag = True
						break
					if tmp == '' or flag:
						break
					sendlen += len(tmp)
					progress(sendlen, statres.st_size)		
				
				print 'aaa'
				print 'bbbbbbbbbb'
				if flag:
					print 'transfer data error'
					self.file.close()
				elif self.recvresponse() != 'FILETRANSFER OK':
					self.file.close()
					print 'transfer data may be ok or error'
				else:
					print 'complete	!'
				print 'aaaaaaaaaaaaaaaaaaaa'

			elif self.cmd.startswith('get'):
				print self.cmd
				print '----get start'
				self.writesockhandler(self.cmd + '\n')
				self.fileinfo = ''
				chunklen = 0
				while True:	
					try:
						chunkdata = self.sock.recv(8 * 1024)
						print chunkdata
						l = len(chunkdata)
						chunklen += l
						if l == 0:
							break
						self.fileinfo += chunkdata
						if self.fileinfo.find('\n') != -1:
							break;
					except (IOError, OSError) as e:
						if geterrnofrome(e) in ERRNO_WOULDBLOCK:
							break
						elif geterrnofrome(e) == errno.EBADF:
							return -1
						else:
							return -1
				
				print 'fileinfo : ' + self.fileinfo

				x = self.fileinfo.split(' ') 
				print x
				self.filename = x[0]
				self.filelen = int(x[1])
				if self.filename.find(':') != -1:
					print 'filename ":" not allowed'
					continue
				try:
					self.file = open(self.filename, 'wb+')
				except (OSError, IOError) as e:
					if self.file: 	self.file.close()
					print 'open file:' + self.filename + 'error' 
					continue

                                chunklen = 0
                                while True:
					try:
						chunkdata = self.sock.recv(8 * 1024)
						l = len(chunkdata)
						chunklen += l
						print chunkdata
						self.file.write(chunkdata)
						self.file.flush()
						if l == 0 or chunklen >= self.filelen:
							break
					except (IOError, OSError) as e:
						if geterrnofrome(e) in ERRNO_WOULDBLOCK:
							break
						elif geterrnofrome(e) == errno.EBADF:
							return -1
						else:
							return -1
				
				print 'complete	!'

			elif self.cmd.startswith('ls'):
				tmp = 'ls\n'
				print tmp
				if self.writesockhandler(tmp) != len(tmp):
					print 'send ls cmd error'
				print tmp
				resp = self.recvresponse()
				x = resp.split(' ')
				for y in x:
					print y 
				print 'total: ' + str(len(x))
			elif self.cmd.startswith('cd'):
				tmp = self.cmd + '\n'
				print 'cd --------- ' + self.cmd
                                if self.writesockhandler(tmp) != len(tmp):
                                        print 'send cmd cmd error'
				
				resp = self.recvresponse()
				x = resp.split(' ')
				if x[0] == 'CDOK': 	self.prompt = x[1]
				else:			print resp
			
if __name__ == '__main__':			
	client = socketclient()

	if client.init() is not None:
		print 'init client error!'
		exit(0)
	
	client.prompt = client.recvresponse()
	if client.prompt == None:
		print 'recv connect response error'
		exit(0)
	print "<<<<<welcome to hotmocha's mini fileserver>>>>>"

	client.loop()
